﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO;
using SosaAnalysisModule.Data;
using System.Windows;

namespace SosaAnalysisModule
{
    public class SOSAFileReader
    {
        /// <summary>
        /// parses a csv file to create and fill a SosaData object
        /// </summary>
        /// <param name="path">path to a CSV</param>
        /// <returns>SosaData</returns>
        public static SosaData CreateSosaData(String path)
        {
            SosaData parsedData = new SosaData();
            List<string[]> parsedCSV = new List<string[]>();
            parsedCSV = ParseCSV(path);

            return CreateSosaData(parsedCSV);
        }

        /// <summary>
        /// same as above
        /// </summary>
        /// <param name="parsedCSV">a parsed csv that have been changed to a list of strings</param>
        /// <returns>SosaData</returns>
        public static SosaData CreateSosaData(List<string[]> parsedCSV)
        {
            SosaData parsedData = new SosaData();

            //parsing for Experiment ID, Version, Subject, and Date
            parsedData.ExperimentID = parsedCSV.ElementAt(0)[1];
            parsedData.Version = parsedCSV.ElementAt(1)[1];
            parsedData.Subject = parsedCSV.ElementAt(2)[1];

            //parsing date, csv has a comma in the date. this combines those 2 strings
            String date1 = parsedCSV.ElementAt(3)[1].Substring(1);
            String date2 = parsedCSV.ElementAt(3)[2];
            if(!date2.Equals(""))
                date2 = date2.Substring(0, date2.Length - 1);
            parsedData.Date = date1 + date2;

            //nextElement starts at 6 to skip title and label lines
            int nextElement = 6;

            /*
             * The following loops create an object and put them in a list
             * nextElement is used to pull data out of the csv list
             */
            int numPegs = 0;
            //used for loops while storing distances between pegs
            //parse Stimuli Presentation
            List<StimuliPresentation> presentationList = new List<StimuliPresentation>();
            while (true)
            {
                StimuliPresentation temp = new StimuliPresentation();
                temp.ID = parsedCSV.ElementAt(nextElement)[0];
                temp.Label = parsedCSV.ElementAt(nextElement)[1];
                presentationList.Add(temp);
                nextElement++;
                if (nextElement == parsedCSV.Count) return null;
                if (parsedCSV.ElementAt(nextElement)[0].Equals("Subject Initial Preview:")) break;
            }
            parsedData.PresentationOrder = presentationList.ToArray();
            numPegs = parsedData.PresentationOrder.Length;

            //Initial Preview
            parsedData.InitialPreviewTime = parsedCSV.ElementAt(nextElement)[1];
            nextElement++;
            //Experiment Start
            parsedData.ExperimentStartTime = parsedCSV.ElementAt(nextElement)[1];

            //3 is added to the nextElement variable to put it past the title and labels
            nextElement += 3;

            //Parse subject Actions
            List<String> uniques = new List<String>();
            List<SubjectAction> actionList = new List<SubjectAction>();
            while (true)
            {
                SubjectAction temp = new SubjectAction();
                temp.Time = parsedCSV.ElementAt(nextElement)[0];
                temp.ID = parsedCSV.ElementAt(nextElement)[1];
                temp.Label = parsedCSV.ElementAt(nextElement)[2];

                //each point is in two elements that look like: "(x and y)"
                //this removes the parenthesis and quotation and changes the string to a float
                String x = parsedCSV.ElementAt(nextElement)[3].Substring(2);
                String y = parsedCSV.ElementAt(nextElement)[4];
                y = y.Substring(0, y.Length - 2);
                double xFloat = double.Parse(x);
                double yFloat = double.Parse(y);
                Point a = new Point(xFloat, yFloat);
                temp.From = a;

                x = parsedCSV.ElementAt(nextElement)[5].Substring(2); ;
                y = parsedCSV.ElementAt(nextElement)[6];
                y = y.Substring(0, y.Length - 2);
                xFloat = double.Parse(x);
                yFloat = double.Parse(y);
                Point b = new Point(xFloat, yFloat);
                temp.To = b;

                actionList.Add(temp);

                //check to see if this label has been seen before
                Boolean seenUnique = false;
                for (int i = 0; i < uniques.Count; i++)
                {
                    if (uniques[i].Equals(temp.Label)) seenUnique = true;
                }
                if (seenUnique == false) uniques.Add(temp.Label);


                nextElement++;
                if (nextElement == parsedCSV.Count) return null;
                if (parsedCSV.ElementAt(nextElement)[0].Equals("Final Positions:")) break;
            }
            if (presentationList.Count != uniques.Count) { System.Windows.Forms.MessageBox.Show("Need to use all of the pegs before you can run Image Composer. Do not save the Composite Image."); return null; }
            parsedData.SubjectActions = actionList.ToArray();

            nextElement += 2;

            //Parse final positions
            List<FinalPosition> finalPositionList = new List<FinalPosition>();
            while (true)
            {
                FinalPosition temp = new FinalPosition();
                temp.ID = parsedCSV.ElementAt(nextElement)[0];
                temp.Label = parsedCSV.ElementAt(nextElement)[1];

                String x = parsedCSV.ElementAt(nextElement)[2].Substring(2); ;
                String y = parsedCSV.ElementAt(nextElement)[3];
                y = y.Substring(0, y.Length - 2);
                double xFloat = double.Parse(x);
                double yFloat = double.Parse(y);
                Point a = new Point(xFloat, yFloat);
                temp.position = a;

                finalPositionList.Add(temp);

                nextElement++;
                if (nextElement == parsedCSV.Count) return null;
                if (parsedCSV.ElementAt(nextElement)[0].Equals("Distances:")) break;
            }
            parsedData.FinalPositions = finalPositionList.ToArray();
            nextElement += 2;

            //Initilize Distance Matrix
            parsedData.Distances = new double[numPegs][];
            //Populate Distance Matrix
            for (int i = 0; i < numPegs; i++)
            {
                parsedData.Distances[i] = new double[numPegs];
                for (int j = 0; j < numPegs; j++)
                {
                    if (i == j)
                        parsedData.Distances[i][j] = 0;
                    else
                        parsedData.Distances[i][j] = Convert.ToDouble(parsedCSV.ElementAt(nextElement)[1 + j]);
                }
                nextElement++;
            }

            return parsedData;
        }

        /// <summary>
        /// changes a csv file to a list of strings
        /// </summary>
        /// <param name="path">a path to a csv file</param>
        /// <returns>a list of strings</returns>
        public static List<string[]> ParseCSV(string path)
        {
            List<string[]> parsedCSV = new List<string[]>();

            try
            {
                using (StreamReader readFile = new StreamReader(path))
                {
                    string line;
                    string[] row;

                    //adds each row to the list, does not add empty rows
                    while ((line = readFile.ReadLine()) != null)
                    {
                        row = line.Split(',');
                        if (!row[0].Equals("")) parsedCSV.Add(row);
                    }
                }
            }
            catch (Exception e)
            {

            }

            return parsedCSV;
        }
    }
}
